package com.ld.shieldsb.common.web.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.springframework.web.util.HtmlUtils;

import com.ld.shieldsb.common.core.util.JsoupUtil;
import com.ld.shieldsb.common.core.util.StringUtils;

/**
 * 拦截xss注入的过滤器的请求封装器
 * 
 * @ClassName XssHttpServletRequestWrapper
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2018年11月15日 上午11:40:00
 *
 */
public class XssRequestWrapper extends HttpServletRequestWrapper {

    private HttpServletRequest orgRequest = null;
    private String richTextNameRegex = null; // 富文本编辑器的name名称的正则表达式
    private String ignoreParamRegex = null; // 不处理的字段的正则表达式

    public XssRequestWrapper(HttpServletRequest request, String richTextName, String ignoreParam) {
        super(request);
        orgRequest = request;
        this.richTextNameRegex = richTextName;
        this.ignoreParamRegex = ignoreParam;
    }

    /**
     * 覆盖getParameter方法，将参数值做xss过滤。<br/>
     * 如果需要获得原始的值，则通过super.getParameterValues(name)来获取<br/>
     * 如果需要获取原始值可以通过getParameterMap获取
     */
    @Override
    public String getParameter(String name) {
//        name = cleanXSS(name);
        String value = super.getParameter(name);
        if (StringUtils.isNotBlank(value)) {
            super.setAttribute(name + "_orig", value);
            value = cleanXSS(value, isRichTextByName(name), isIgnoreParamByName(name));
        }
        return value;
    }

    /**
     * 根据参数名判断是否是富文本编辑器内容
     * 
     * @Title isRichTextByName
     * @author 吕凯
     * @date 2018年7月2日 上午9:46:31
     * @param name
     * @return boolean
     */
    private boolean isRichTextByName(String name) {
        if (name == null) {
            return false;
        }
        return StringUtils.isNotBlank(richTextNameRegex) && name.matches(richTextNameRegex);
    }

    /**
     * 
     * 根据参数名判断是否是忽略处理的字段
     * 
     * @Title isIgnoreParamByName
     * @author 吕凯
     * @date 2021年1月28日 上午11:31:31
     * @param name
     * @return boolean
     */
    private boolean isIgnoreParamByName(String name) {
        if (name == null) {
            return false;
        }
        return StringUtils.isNotBlank(ignoreParamRegex) && name.matches(ignoreParamRegex);
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] arr = super.getParameterValues(name);
        if (arr != null) {
            String[] arrOrig = new String[arr.length];
            super.setAttribute(name + "_orig", arrOrig);
            for (int i = 0; i < arr.length; i++) {
                arrOrig[i] = arr[i];
                arr[i] = cleanXSS(arr[i], isRichTextByName(name), isIgnoreParamByName(name));
            }
        }
        return arr;
    }

    /**
     * 覆盖getHeader方法，将参数值做xss过滤。<br/>
     * 如果需要获得原始的值，则通过super.getHeaders(name)来获取<br/>
     * getHeaderNames 也可能需要覆盖
     */
    @Override
    public String getHeader(String name) {
//        name = cleanXSS(name);
        String value = super.getHeader(name);
        if (StringUtils.isNotBlank(value)) {
            value = cleanXSS(value, false, false);
        }
        return value;
    }

    /**
     * 获取最原始的request
     * 
     * @return
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    }

    /**
     * 清除xss
     * 
     * @Title cleanXSS
     * @author 吕凯
     * @date 2018年11月24日 上午11:36:46
     * @param value
     * @param isRichText
     *            是否为富文本（保留部分html标签）
     * @param isIgnoreParam
     *            是否为忽略处理的字段，不进行任何处理
     * @return String
     */
    private String cleanXSS(String value, boolean isRichText, boolean isIgnoreParam) {
        // You'll need to remove the spaces from the html entities below

//        value = cleanXSSSimple(value);
        if (!isIgnoreParam) { // 不处理
            if (isRichText) { // 富文本编辑器需要保留部分html标签
                value = JsoupUtil.clean(value); // StringUtils.stripXSSTag
            } else { // 移除所有html标签
                value = HtmlUtils.htmlEscape(value);
//            value = JsoupUtil.cleanAllHtml(value);
//            value = StringUtils.escapeHtml(value);
            }
        }
        return value;

    }

    /*    private String cleanXSSSimple(String value) {
        // You'll need to remove the spaces from the html entities below
        value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
        value = value.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
        value = value.replaceAll("'", "&#39;");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("alert\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("script", "");
    
        return value;
    
    }*/

    public static void main(String[] args) {

        String ss = "<ScRiPt >alert('xss');<\\/script>"; // 此处的><需要转义
        String ss1 = "1\" autofocus onfocus=alert(document.cookie) x=\""; // 根据页面input的value是单引号还是双引号来处理,注意此处的 ' "需要转义
        String ss0 = "2<3,特殊是>3>21sss&nbsp;&nbsp;&nbsp;&nbsp;123&a=b"; // 此处的><需要转义
        System.out.println("cleanAllHtml==========" + JsoupUtil.cleanAllHtml(ss));
        System.out.println("escapeHtml==========" + StringUtils.escapeHtml(JsoupUtil.cleanAllHtml(ss)));
//        System.out.println("ESAPI==========" + ESAPI.encoder().canonicalize(ss));
//        System.out.println("forHtmlContent==========" + Encode.forHtmlContent(ss));
//        System.out.println("forCssString==========" + Encode.forCssString(ss));
        System.out.println("HtmlUtils==========" + HtmlUtils.htmlEscape(ss));
        System.out.println();

        System.out.println("cleanAllHtml==========" + JsoupUtil.cleanAllHtml(ss1));
        System.out.println("escapeHtml==========" + StringUtils.escapeHtml(JsoupUtil.cleanAllHtml(ss1)));
//        System.out.println("ESAPI==========" + ESAPI.encoder().encodeForHTML(ss1));
//        System.out.println("forHtmlContent==========" + Encode.forHtmlContent(ss1));
//        System.out.println("forJavaScript==========" + Encode.forJavaScript(ss1));
//        System.out.println("forCssString==========" + Encode.forCssString(ss1));
        System.out.println("HtmlUtils==========" + HtmlUtils.htmlEscape(ss1));
        System.out.println();

        System.out.println("cleanAllHtml==========" + JsoupUtil.cleanAllHtml(ss0));
        System.out.println("escapeHtml==========" + StringUtils.escapeHtml(JsoupUtil.cleanAllHtml(ss0)));
//        System.out.println("ESAPI==========" + ESAPI.encoder().encodeForHTML(ss0));
//        System.out.println("ESAPI==========" + ESAPI.encoder().encodeForCSS(ss0));
//        System.out.println("forHtmlContent==========" + Encode.forHtmlContent(ss0));
//        System.out.println("forJavaScript==========" + Encode.forJavaScript(ss0));
//        System.out.println("forCssString==========" + Encode.forCssString(ss0));
        System.out.println("HtmlUtils==========" + HtmlUtils.htmlEscape(ss0));

    }

}